package org.hzz.api.coupon.controller;

import io.gitee.pkmer.common.collection.CollUtil;
import io.gitee.pkmer.convention.exception.arg.AppArgumentNotValidException;
import io.gitee.pkmer.convention.page.PageResponse;
import io.gitee.pkmer.convention.page.query.PageQuery;
import io.gitee.pkmer.security.context.AppContextHolder;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import org.hzz.api.coupon.CouponApi;
import org.hzz.application.command.*;
import org.hzz.application.command.user.ShowCouponCmd;
import org.hzz.application.service.PromotionsCmdService;
import io.gitee.pkmer.convention.controller.BaseController;
import io.gitee.pkmer.convention.result.Result;
import org.hzz.promotions.types.enums.coupon.IssueType;
import org.hzz.promotions.types.enums.coupon.TermType;
import org.hzz.promotions.types.req.AddCouponReq;
import lombok.Setter;
import org.hzz.promotions.types.req.CouponPageQuery;
import org.hzz.promotions.types.req.IssueCouponReq;
import org.hzz.promotions.types.vo.CouponPageVo;
import org.hzz.promotions.types.vo.CouponVo;
import org.hzz.promotions.types.vo.ShowCouponVo;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * @author <a href="mailto:1193094618@qq.com">pkmer</a>
 * <br>
 * <a href = "https://gitee.com/pkmer/sonatype-central-publisher">Code Repository</a>
 * At 2024/8/29
 */
@RestController
public class CouponController extends BaseController implements CouponApi {

    @Setter(onMethod_ = {@Autowired})
    private PromotionsCmdService cmdService;

    @Setter(onMethod_ = {@Autowired})
    private Validator validator;

    @Override
    public Result<String> saveCoupon(AddCouponReq addCouponReq) {
        logger.info("saveCoupon: {}", addCouponReq.getName());

        Long userId = AppContextHolder.userContextHolder.getUser().getId();


        Long id = Converter.INSTANCE
                .toAddCouponCmd(addCouponReq)
                .setCreater(userId)
                .setUpdater(userId)
                .executeWithResult(cmdService);
        return success(id.toString());
    }

    @Override
    public Result<CouponVo> getCoupon(String id) {
        logger.info("获取优惠券详情");
        CouponVo couponVo = GetCouponCmd.commandOf(Long.parseLong(id))
                .executeWithResult(cmdService);
        return success(couponVo);
    }

    @Override
    public Result<PageResponse<CouponPageVo>> pageQuery(CouponPageQuery pageQuery) {
        logger.info("分页查询优惠券");
        PageResponse<CouponPageVo> pages = CouponPageQueryCmd
                .commandOf(pageQuery)
                .executeWithResult(cmdService);

        return success(pages);
    }


    @Override
    public Result<Void> beginIssue(String id, IssueCouponReq issueCouponReq) {
        validateIssueCouponReq(issueCouponReq);
        logger.info("发布优惠券");
        new IssueCouponCmd()
                .setId(Long.parseLong(id))
                .setIssueBeginTime(issueCouponReq.getIssueBeginTime())
                .setTermBeginTime(issueCouponReq.getTermBeginTime())
                .setTermDays(issueCouponReq.getTermDays())
                .setIssueEndTime(issueCouponReq.getIssueEndTime())
                .execute(cmdService);

        return success();
    }

    @Override
    public Result<Void> pauseCoupon(String id) {
        logger.info("暂停发放优惠券 id = {}",id);
        PauseCouponCmd.commandOf(Long.parseLong(id))
                .execute(cmdService);
        return success();
    }

    @Override
    public Result<Void> deleteCoupon(String id) {
        logger.info("删除优惠券 id = {}",id);
        DeleteCouponCmd.commandOf(Long.parseLong(id))
                .execute(cmdService);
        return success();
    }

    @Override
    public Result<Void> updateCoupon(String id, AddCouponReq addCouponReq) {

        logger.info("更新优惠券信息 id = {}",id);

        Long userId = AppContextHolder.userContextHolder.getUser().getId();
        Converter.INSTANCE
                .toUpdateCouponCmd(addCouponReq)
                .setId(Long.parseLong(id))
                .setCreater(userId)
                .setUpdater(userId)
                .execute(cmdService);

        return success();
    }

    @Override
    public Result<PageResponse<ShowCouponVo>> listCoupon(PageQuery pageQuery) {
        logger.info("查询用户可以领取的优惠券");
        Long userId = AppContextHolder.userContextHolder.getUser().getId();
        PageResponse<ShowCouponVo> showCouponVoPageResponse = ShowCouponCmd.commandOf(userId, pageQuery)
                .executeWithResult(cmdService);
        return success(showCouponVoPageResponse);
    }


    /**
     * 分组校验参数
     * @param issueCouponReq 发布优惠券请求参数
     */
    private void validateIssueCouponReq(IssueCouponReq issueCouponReq) {
        Set<ConstraintViolation<IssueCouponReq>> sets = new HashSet<>();

        // 分组校验发放方式
        if(issueCouponReq.getIssueType() == IssueType.NOW){
            //
            Set<ConstraintViolation<IssueCouponReq>> validate = validator.validate(issueCouponReq, IssueCouponReq.IssueNowGroup.class);
            sets.addAll(validate);
        }else{
            Set<ConstraintViolation<IssueCouponReq>> validate = validator.validate(issueCouponReq, IssueCouponReq.IssueLaterGroup.class);
            sets.addAll(validate);
        }

        // 分组校验使用限制方式
        if(issueCouponReq.getTermType() == TermType.DAYS){
            Set<ConstraintViolation<IssueCouponReq>> validate = validator.validate(issueCouponReq, IssueCouponReq.TermDaysGroup.class);
            sets.addAll(validate);
        }else{
            Set<ConstraintViolation<IssueCouponReq>> validate = validator.validate(issueCouponReq, IssueCouponReq.TermTimeGroup.class);
            sets.addAll(validate);
        }

        if(CollUtil.isNotEmpty(sets)){
            throw new AppArgumentNotValidException(sets);
        }
    }

    @Mapper
    interface Converter{
        Converter INSTANCE = Mappers.getMapper(Converter.class);
        AddCouponCmd toAddCouponCmd(AddCouponReq addCouponReq);

        UpdateCouponCmd toUpdateCouponCmd(AddCouponReq addCouponReq);
    }
}
